<?php
/**
 * ControllerCommand class file.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @link http://www.yiiframework.com/
 * @copyright Copyright &copy; 2008-2011 Yii Software LLC
 * @license http://www.yiiframework.com/license/
 * @version $Id: ControllerCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
 */

/**
 * ControllerCommand generates a controller class.
 *
 * @author Qiang Xue <qiang.xue@gmail.com>
 * @version $Id: ControllerCommand.php 2799 2011-01-01 19:31:13Z qiang.xue $
 * @package system.cli.commands.shell
 * @since 1.0
 */
class ControllerCommand extends CConsoleCommand
{
    /**
     * @var string the directory that contains templates for the model command.
     * Defaults to null, meaning using 'framework/cli/views/shell/controller'.
     * If you set this path and some views are missing in the directory,
     * the default views will be used.
     */
    public $templatePath;
    
    public function getHelp()
    {
        return <<<EOD
USAGE
  controller <controller-ID> [action-ID] ...

DESCRIPTION
  This command generates a controller and views associated with
  the specified actions.

PARAMETERS
 * controller-ID: required, controller ID, e.g., 'post'.
   If the controller should be located under a subdirectory,
   please specify the controller ID as 'path/to/ControllerID',
   e.g., 'admin/user'.

   If the controller belongs to a module, please specify
   the controller ID as 'ModuleID/ControllerID' or
   'ModuleID/path/to/Controller' (assuming the controller is
   under a subdirectory of that module).

 * action-ID: optional, action ID. You may supply one or several
   action IDs. A default 'index' action will always be generated.

EXAMPLES
 * Generates the 'post' controller:
        controller post

 * Generates the 'post' controller with additional actions 'contact'
   and 'about':
        controller post contact about

 * Generates the 'post' controller which should be located under
   the 'admin' subdirectory of the base controller path:
        controller admin/post

 * Generates the 'post' controller which should belong to
   the 'admin' module:
        controller admin/post

NOTE: in the last two examples, the commands are the same, but
the generated controller file is located under different directories.
Yii is able to detect whether 'admin' refers to a module or a subdirectory.

EOD;
    }
    
    /**
     * Execute the action.
     * @param array command line parameters specific for this command
     */
    public function run($args)
    {
        if (! isset ( $args [0] )) {
            echo "Error: controller name is required.\n";
            echo $this->getHelp ();
            return;
        }
        
        $module = Yii::app ();
        $controllerID = $args [0];
        if (($pos = strrpos ( $controllerID, '/' )) === false) {
            $controllerClass = ucfirst ( $controllerID ) . 'Controller';
            $controllerFile = $module->controllerPath . DIRECTORY_SEPARATOR . $controllerClass . '.php';
            $controllerID [0] = strtolower ( $controllerID [0] );
        } else {
            $last = substr ( $controllerID, $pos + 1 );
            $last [0] = strtolower ( $last [0] );
            $pos2 = strpos ( $controllerID, '/' );
            $first = substr ( $controllerID, 0, $pos2 );
            $middle = $pos === $pos2 ? '' : substr ( $controllerID, $pos2 + 1, $pos - $pos2 );
            
            $controllerClass = ucfirst ( $last ) . 'Controller';
            $controllerFile = ($middle === '' ? '' : $middle . '/') . $controllerClass . '.php';
            $controllerID = $middle === '' ? $last : $middle . '/' . $last;
            if (($m = Yii::app ()->getModule ( $first )) !== null)
                $module = $m;
            else {
                $controllerFile = $first . '/' . $controllerClass . '.php';
                $controllerID = $first . '/' . $controllerID;
            }
            
            $controllerFile = $module->controllerPath . DIRECTORY_SEPARATOR . str_replace ( '/', DIRECTORY_SEPARATOR, $controllerFile );
        }
        
        $args [] = 'index';
        $actions = array_unique ( array_splice ( $args, 1 ) );
        
        $templatePath = $this->templatePath === null ? YII_PATH . '/cli/views/shell/controller' : $this->templatePath;
        
        $list = array (basename ( $controllerFile ) => array ('source' => $templatePath . DIRECTORY_SEPARATOR . 'controller.php', 'target' => $controllerFile, 'callback' => array ($this, 'generateController' ), 'params' => array ($controllerClass, $actions ) ) );
        
        $viewPath = $module->viewPath . DIRECTORY_SEPARATOR . str_replace ( '/', DIRECTORY_SEPARATOR, $controllerID );
        foreach ( $actions as $name ) {
            $list [$name . '.php'] = array ('source' => $templatePath . DIRECTORY_SEPARATOR . 'view.php', 'target' => $viewPath . DIRECTORY_SEPARATOR . $name . '.php', 'callback' => array ($this, 'generateAction' ), 'params' => array ('controller' => $controllerClass, 'action' => $name ) );
        }
        
        $this->copyFiles ( $list );
        
        if ($module instanceof CWebModule)
            $moduleID = $module->id . '/';
        else
            $moduleID = '';
        
        echo <<<EOD

Controller '{$controllerID}' has been created in the following file:
    $controllerFile

You may access it in the browser using the following URL:
    http://hostname/path/to/index.php?r={$moduleID}{$controllerID}

EOD;
    }
    
    public function generateController($source, $params)
    {
        if (! is_file ( $source )) // fall back to default ones
            $source = YII_PATH . '/cli/views/shell/controller/' . basename ( $source );
        return $this->renderFile ( $source, array ('className' => $params [0], 'actions' => $params [1] ), true );
    }
    
    public function generateAction($source, $params)
    {
        if (! is_file ( $source )) // fall back to default ones
            $source = YII_PATH . '/cli/views/shell/controller/' . basename ( $source );
        return $this->renderFile ( $source, $params, true );
    }
}